package com.google.code.jtasks.client.ui;

import com.google.code.jtasks.client.exceptions.TerminateException;
import com.google.code.jtasks.client.state.ClientState;
import com.google.code.jtasks.client.ui.commands.DefaultCommand;
import com.google.common.collect.ImmutableSortedMap;
import com.google.inject.Inject;
import com.googlecode.lanterna.input.Key;

import java.util.Map;

/**
 * Обрабатывает команды от пользователя и выводит меню и статусную информацию.
 */
public class CommandDispatcher {
    private final Map<Character, Command> commands;
    private final DefaultCommand defaultCommand;
    private final ScreenHelper helper;
    private final ClientState clientState;

    @Inject
    CommandDispatcher(Map<Character, Command> commands, DefaultCommand defaultCommand,
                      ScreenHelper helper, ClientState clientState) {
        this.helper = helper;
        this.clientState = clientState;
        this.commands = ImmutableSortedMap.copyOf(commands);
        this.defaultCommand = defaultCommand;
    }

    /**
     * Основной цикл обработки ввода пользователя. В бесконечном цикле ожидает нажатия символа и определяет, к какой
     * команде символ относится, после чего выполняет эту команду. Если символ неизвестен, выполняет команду
     * {@link #defaultCommand}. Чтобы сигнализировать о том, что следует завершить цикл, команда может выбросить
     * {@link TerminateException}.
     */
    public void mainLoop() {
        while (true) {
            helper.clear();
            drawStatus();
            helper.refresh();

            Key key = helper.readKey();
            Command command = dispatchCommand(key.getCharacter());
            try {
                helper.clear();
                command.execute();
            } catch (TerminateException e) {
                break;
            }
        }
    }

    /**
     * Выводит статусное сообщение и меню.
     */
    private void drawStatus() {
        int y = 2;
        helper.drawString(5, y, "Current tasks service URI: " + clientState.serviceUri());
        y += 2;

        helper.drawString(5, y++, "Available commands:");
        int i = 0;
        for (Map.Entry<Character, Command> entry : commands.entrySet()) {
            Command command = entry.getValue();
            String line = String.format("%c) %s", entry.getKey(), command.name());
            helper.drawString(5, y + 2 * i, line);
            line = String.format("   %s", command.description());
            helper.drawString(5, y + 2 * i + 1, line);
            ++i;
        }
        y = 2 + 3*i + 2;

        String msg = "Your choice?";
        helper.drawString(5, y, msg);
        helper.moveCursorTo(5 + msg.length() + 1, y);

        helper.refresh();
    }

    /**
     * Выбирает команду по заданному символу. Если команды не найдено, используется команда по умолчанию.
     * @param ch символ-идентификатор команды
     * @return команда
     * @see com.google.code.jtasks.client.modules.CommandsModule
     */
    private Command dispatchCommand(char ch) {
        Command command = commands.get(ch);
        if (command == null) {
            command = defaultCommand;
        }
        return command;
    }
}
